/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.to.aboomy.bannersample.indicator;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.StackLayout;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;

/**
 * RevealLayout
 *
 * @since 2021-07-29
 */
public class RevealLayout extends StackLayout {
    private static final int NUM_2 = 2;
    private static final int NUM_5 = 5;
    private static final int DEFAULT_DURATION = 600;
    /**
     * 圆心坐标
     */
    private int mClipCenterX = 0;
    /**
     * 圆心坐标
     */
    private int mClipCenterY = 0;

    /**
     * 半径
     */
    private float mClipRadius = 0;
    private boolean mIsContentShown = true;

    private AnimatorProperty mAnimation;

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public RevealLayout(Context context) {
        this(context, null);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrs 属性
     */
    public RevealLayout(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrs 属性
     * @param styleName 样式名
     */
    public RevealLayout(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
    }

    /**
     * getClipRadius
     *
     * @return mClipRadius
     */
    public float getClipRadius() {
        return mClipRadius;
    }

    /**
     * 设置半径
     *
     * @param clipRadius 半径
     */
    public void setClipRadius(float clipRadius) {
        mClipRadius = clipRadius;
        invalidate();
    }

    /**
     * isContentShown
     *
     * @return mIsContentShown
     */
    public boolean isContentShown() {
        return mIsContentShown;
    }

    /**
     * setContentShown
     *
     * @param isContentShown boolean
     */
    public void setContentShown(boolean isContentShown) {
        mIsContentShown = isContentShown;
        if (mIsContentShown) {
            mClipRadius = 0;
        } else {
            mClipRadius = getMaxRadius(mClipCenterX, mClipCenterY);
        }
        invalidate();
    }

    /**
     * 展示
     */
    public void show() {
        show(DEFAULT_DURATION);
    }

    /**
     * 展示时间
     *
     * @param duration 时间
     */
    public void show(int duration) {
        show(duration, null);
    }

    /**
     * 展示位置
     *
     * @param x1 x坐标
     * @param y1 y坐标
     */
    public void show(int x1, int y1) {
        show(x1, y1, DEFAULT_DURATION, null);
    }

    /**
     * 展示
     *
     * @param listener 状态监听
     */
    public void show(Animator.StateChangedListener listener) {
        show(DEFAULT_DURATION, listener);
    }

    /**
     * 显示
     *
     * @param duration 持续时间
     * @param listener 状态监听
     */
    public void show(int duration, Animator.StateChangedListener listener) {
        show(getWidth(), getHeight() / NUM_2, duration, listener);
    }

    /**
     * 显示
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param listener 状态监听
     */
    public void show(int x1, int y1, Animator.StateChangedListener listener) {
        show(x1, y1, DEFAULT_DURATION, listener);
    }

    /**
     * 展示
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param duration 持续时间
     */
    public void show(int x1, int y1, int duration) {
        show(x1, y1, duration, null);
    }

    /**
     * show
     *
     * @param x1 坐标
     * @param y1 坐标
     * @param duration 持续时间
     * @param listener 状态监听
     */
    public void show(int x1, int y1, int duration, final Animator.StateChangedListener listener) {
        mClipCenterX = x1;
        mClipCenterY = y1;

        mAnimation = createAnimatorProperty();
        mAnimation.setCurveType(Animator.CurveType.DECELERATE);
        mAnimation.setDuration(duration);
        mAnimation.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                mIsContentShown = true;
                if (listener != null) {
                    listener.onStart(animator);
                }
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                if (listener != null) {
                    listener.onEnd(animator);
                }
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimation.start();
    }

    /**
     * 展示半径动画
     *
     * @param changeValue 变化值
     */
    public void showClipAnimation(float changeValue) {
        showClipAnimation(getWidth(), getHeight() / NUM_2, changeValue);
    }

    /**
     * showClipAnimation
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param changeValue 变化值
     */
    public void showClipAnimation(int x1, int y1, float changeValue) {
        mClipCenterX = x1;
        mClipCenterY = y1;
        final float maxRadius = getMaxRadius(x1, y1);
        setClipRadius(changeValue * maxRadius);
    }

    /**
     * hideClipAnimation
     *
     * @param changeValue 变化值
     * @param offsetPx 偏移量
     */
    public void hideClipAnimation(float changeValue, int offsetPx) {
        if (offsetPx > 0) {
            hideClipAnimation(getDeviceWidth(), getHeight() / NUM_2, changeValue);
        } else {
            hideClipAnimation(0, getHeight() / NUM_2, changeValue * NUM_5);
        }
    }

    /**
     * hideClipAnimation
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param changeValue 变化值
     */
    public void hideClipAnimation(int x1, int y1, float changeValue) {
        final float maxRadius = getMaxRadius(x1, y1);
        if (x1 != mClipCenterX || y1 != mClipCenterY) {
            mClipCenterX = x1;
            mClipCenterY = y1;
            mClipRadius = maxRadius;
        }
        setClipRadius(changeValue * maxRadius);
    }

    private int getDeviceWidth() {
        DisplayAttributes attributes = DisplayManager.getInstance()
                .getDefaultDisplay(getContext()).get().getRealAttributes();
        return attributes.width;
    }

    /**
     * 隐藏
     */
    public void hide() {
        hide(DEFAULT_DURATION);
    }

    /**
     * 隐藏
     *
     * @param duration 持续时间
     */
    public void hide(int duration) {
        hide(getWidth(), getHeight() / NUM_2, duration, null);
    }

    /**
     * 隐藏
     *
     * @param x1 x坐标
     * @param y1 y坐标
     */
    public void hide(int x1, int y1) {
        hide(x1, y1, DEFAULT_DURATION, null);
    }

    /**
     * 隐藏
     *
     * @param listener 状态监听
     */
    public void hide(Animator.StateChangedListener listener) {
        hide(DEFAULT_DURATION, listener);
    }

    /**
     * 隐藏
     *
     * @param duration 持续时间
     * @param listener 状态监听
     */
    public void hide(int duration, Animator.StateChangedListener listener) {
        hide(getWidth() / NUM_2, getHeight() / NUM_2, duration, listener);
    }

    /**
     * 隐藏
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param listener 状态监听
     */
    public void hide(int x1, int y1, Animator.StateChangedListener listener) {
        hide(x1, y1, DEFAULT_DURATION, listener);
    }

    /**
     * 隐藏
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param duration 持续时间
     */
    public void hide(int x1, int y1, int duration) {
        hide(x1, y1, duration, null);
    }

    /**
     * 隐藏
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param duration 持续时间
     * @param listener 状态监听
     */
    public void hide(int x1, int y1, int duration, final Animator.StateChangedListener listener) {
        final float maxRadius = getMaxRadius(x1, y1);
        if (x1 != mClipCenterX || y1 != mClipCenterY) {
            mClipCenterX = x1;
            mClipCenterY = y1;
            mClipRadius = maxRadius;
        }

        mAnimation = createAnimatorProperty();
        mAnimation.setCurveType(Animator.CurveType.DECELERATE);
        mAnimation.setDuration(duration);
        mAnimation.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                mIsContentShown = true;
                if (listener != null) {
                    listener.onStart(animator);
                }
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                if (listener != null) {
                    listener.onEnd(animator);
                }
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimation.start();
    }

    /**
     * next
     */
    public void next() {
        next(DEFAULT_DURATION);
    }

    /**
     * next
     *
     * @param duration 持续时间
     */
    public void next(int duration) {
        next(getWidth() / NUM_2, getHeight() / NUM_2, duration, null);
    }

    /**
     * next
     *
     * @param x1 x坐标
     * @param y1 y坐标
     */
    public void next(int x1, int y1) {
        next(x1, y1, DEFAULT_DURATION, null);
    }

    /**
     * next
     *
     * @param listener 状态监听
     */
    public void next(Animator.StateChangedListener listener) {
        next(DEFAULT_DURATION, listener);
    }

    /**
     * next
     *
     * @param duration 持续时间
     * @param listener 状态监听
     */
    public void next(int duration, Animator.StateChangedListener listener) {
        next(getWidth() / NUM_2, getHeight() / NUM_2, duration, listener);
    }

    /**
     * next
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param listener 状态监听
     */
    public void next(int x1, int y1, Animator.StateChangedListener listener) {
        next(x1, y1, DEFAULT_DURATION, listener);
    }

    /**
     * next
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param duration 持续时间
     */
    public void next(int x1, int y1, int duration) {
        next(x1, y1, duration, null);
    }

    /**
     * next
     *
     * @param x1 x坐标
     * @param y1 y坐标
     * @param duration 时间
     * @param listener 状态监听
     */
    public void next(int x1, int y1, int duration, Animator.StateChangedListener listener) {
        final int childCount = getChildCount();
        if (childCount > 1) {
            for (int i1 = 0; i1 < childCount; i1++) {
                Component child = getComponentAt(i1);
                if (i1 == 0) {
                    moveChildToFront(child);
                }
            }
            show(x1, y1, duration, listener);
        }
    }

    private float getMaxRadius(int x, int y) {
        int h1 = Math.max(x, getWidth() - x);
        int v1 = Math.max(y, getHeight() - y);
        return (float) Math.sqrt(h1 * h1 + v1 * v1);
    }

    /**
     * getmClipCenterX
     *
     * @return int
     */
    public int getClipCenterX() {
        return mClipCenterX;
    }

    /**
     * setmClipCenterX
     *
     * @param clipCenterX
     */
    public void setClipCenterX(int clipCenterX) {
        mClipCenterX = clipCenterX;
    }

    /**
     * getmClipCenterY
     *
     * @return int
     */
    public int getClipCenterY() {
        return mClipCenterY;
    }

    /**
     * setmClipCenterY
     *
     * @param clipCenterY
     */
    public void setClipCenterY(int clipCenterY) {
        mClipCenterY = clipCenterY;
    }
}